'''Authentication and authorization APIs'''

import logging
import hashlib
import base64

from pylons import request, response, session, tmpl_context as c, url
from pylons.i18n import _
from couchdb import client

from pedetra.model import *

log = logging.getLogger(__name__)

class AuthenticationFailure(Exception):
    pass

class AuthorizationFailure(Exception):
    pass

class UserAuth:
    '''Object for the authentication and authorization of users'''
    def __init__(self, user):
        if type(user) == str or type(user) == unicode:
            try:
                user = User(db[user])
                log.info(_('Found user %s by ID %s') % (user.username, user['_id']))
            except client.ResourceNotFound:
                view_results = User.view(db, '_view/user/by_username', key=user)
                if not view_results:
                    raise AuthenticationFailure(_('Unknown username or bad password'))
                for user_object in view_results:
                    user = user_object
                log.info(_('Found user %s by username') % (user.username))
        assert(type(user) == User)
        self.user = user

    def login(self, password):
        '''Check if the inputted password matches what's stored in the database,
        if the hash matches then add the user id to the session information.'''
        salt = self.user.password_salt.decode('base64')
        pwd_hash = hashlib.sha256(salt + password).hexdigest()
        if pwd_hash == self.user.password:
            session['userid'] = self.user['_id']
            session.save()
            log.info(_('User %s authenticated, added id %s to session') % (self.user.username, self.user['_id']))
        else:
            raise AuthenticationFailure(_('Unknown username or bad password'))
    
    actions = [
        'create', 'view', 'view_technical_notes', 'assign', 'assign_to',
        'reassign', 'add_notes', 'add_technical_notes', 'modify_fields',
        'delete_notes', 'delete_technical_notes', 'delete'
    ]
    def check_authorization(self, target, action):
        '''Determine whether a user's able to perform the specified action
        against this object'''
        
        assert(action in actions)
        if type(target) == str or type(target) == unicode:
            try:
                target_typecheck = db[target]
                if target_typecheck['type'] == 'ticket':
                    target = TicketDefinition(db[target_typecheck.form_id])
                elif target_typecheck['type'] == 'ticket_definition':
                    target = TicketDefinition(db[target])
        elif type(target) == Ticket:
            target = TicketDefinition(db[target.form_id])
        assert(type(target) == TicketDefinition)
        # check action against most recent version of this form for this user

    def get_actions(self):
        pass

#create test user if they don't exist..
view_results = User.view(db, '_view/user/by_username', key='foo')
if not view_results:
    n = User()
    n.username = 'foo'
    n.password_salt = 'liwjeoijwoijr09182'.encode('base64')
    n.password = hashlib.sha256(n.password_salt.decode('base64')+'password').hexdigest()
    n.store(db)
